﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;

public class Player : unit
{
    private static Player instance;
    public static Player MyInstance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<Player>();
            }
            return instance;
        }
    }
    private bool canAccelerate = true;
    private Coroutine sd;
    private Coroutine sr;
    private Coroutine hr;
    private float walkSpd;
    private float speed;
    private float runSpd;
    [SerializeField]
    private int basicAP;
    [SerializeField]
    private int tenthAP;
    [SerializeField]
    private int fiftyAP;
    [SerializeField]
    private int hundAP;
    [SerializeField]
    private int debugExpGainAmount;
    [SerializeField]
    private GameObject LvlUpEffect;
    public stats Stamina { get => stamina; set => stamina = value; }
    [SerializeField]
    private int staminaRegen = 1;
    [SerializeField]
    private int healthRegen = 0;
    [SerializeField]
    private int manaRegen = 0;
    private bool canRegenStamina=true;
    private bool canRegenHealth=true;
    private bool canRegenMana=true;
    public stats Mana { get => mana; set => mana = value; }
    public int MyGold { get; set; }
    public List<IInteractable> MyInteractables { get => interactables; set => interactables = value; }

    public IInteractable MyInteractable { get => interactable; set => interactable = value; }
    public stats MyExp { get => exp; set => exp = value; }
    public List<enemy> MyAttackers { get => attackers; set => attackers = value; }

    //AbilityPoints ap;
    [SerializeField]
    float rad = 1;
    Vector3 MousePos;
    Vector3 position;
   
    [SerializeField]
    private GearSoket[] sokets;

    private string playerName;

    [SerializeField]
    private stats mana;
    [SerializeField]
    private int initMana;

    [SerializeField]
    private stats stamina;
    [SerializeField]
    private int initStamina;

    [SerializeField]
    private stats exp;
    
    [SerializeField]
    private blockCtrl[] blocks;

    [SerializeField]
    private Text goldText;

    [SerializeField]
    private Profession profession;

    private IInteractable interactable;
    private List<IInteractable> interactables = new List<IInteractable>();
    private int dirIndex;

    private List<enemy> attackers = new List<enemy>();
    
    protected void Awake()
    {       
        HPbarShow = false; //to UI
        
    }
    
    new void Update()
    {
        keyinput();
        move();
        goldText.text=MyGold.ToString()+" G";
        if (stamina.myVal < stamina.maxVal && canRegenStamina)
        {
            StartCoroutine(StatRegen(staminaRegen,3, stamina));
            
        }
        if (Health.myVal < Health.maxVal && canRegenHealth)
        {
           StartCoroutine(StatRegen(healthRegen, 3, Health));
        }
        if (Mana.myVal < Mana.maxVal && canRegenMana)
        {
            StartCoroutine(StatRegen(manaRegen, 3, Mana));
        }
    }
    protected override void move()
    {
        base.move();
        prb.velocity = direction.normalized * speed;
        

    }
    private void keyinput()
    {
        walkSpd = MySpd;
        runSpd = walkSpd * 1.5f;
        Xdir = Input.GetAxis("Horizontal");
        Ydir = Input.GetAxis("Vertical");
        
        if (Xdir > 0)//right
        {
            dirIndex = 1;
        }
        if (Ydir > 0)//up
        {
            dirIndex = 0;
        }
        if (Xdir < 0)//left
        {
            dirIndex = 3;
        }
        if (Ydir < 0)//down
        {
            dirIndex = 2;
        }

       if(stamina.myVal == 0 && sd!=null)
        {
            StopCoroutine(sd);
        }

        foreach (string act in keybindsManager.MyInstance.actionBinds.Keys)
        {
            if (Input.GetKeyDown(keybindsManager.MyInstance.actionBinds[act]))
            {
                UIManager.MyInstance.clickActionButton(act);
            }
        }
        if (Input.GetKeyDown(KeyCode.Q))//Debug-Only
        {
            GetXP(debugExpGainAmount);
        }
        
        if (Input.GetKey(KeyCode.LeftShift) && stamina.myVal!=0)
        {
            speed = runSpd;
            if (canAccelerate)
            {
                canAccelerate = false;
                sd = StartCoroutine(StatDrain(1,1,stamina));
            }
            
        }
        else
        {
            speed = walkSpd;
            
            if (sd != null )
            {
                canAccelerate = true;
                StopCoroutine(sd);
                
            }
        }
        
    }

    public void AddAttackers(enemy enemy)
    {
        if (!MyAttackers.Contains(enemy)) {
            MyAttackers.Add(enemy);
        }
    }
    public void RemoveAttackers(enemy enemy)
    {
        if (MyAttackers.Contains(enemy))
        {
            MyAttackers.Remove(enemy);
        }
    }
    private IEnumerator StatDrain(int drainValue, int timeBetweenCalls, stats stat)
    {
        while (true)
        {
            stamina.myVal -= drainValue;
            yield return new WaitForSeconds(timeBetweenCalls);
        }
    }

    private IEnumerator StatRegen(int regenValue, int timeBetweenCalls, stats stat)
    {
        if (stat == stamina)
        {
            canRegenStamina=false;
            stat.myVal += regenValue;
            yield return new WaitForSeconds(timeBetweenCalls);
            canRegenStamina = true;
        }
        else if (stat == Health)
        {
            canRegenHealth = false;
            stat.myVal += regenValue;
            yield return new WaitForSeconds(timeBetweenCalls);
            canRegenHealth = true;
        }
        else
        {
            canRegenMana = false;
            stat.myVal += regenValue;
            yield return new WaitForSeconds(timeBetweenCalls);
            canRegenMana = true;
        }

    }
    private IEnumerator ActionRoutine(ICastable castable)
    { 
        skillBook.MyInstance.useSpell(castable);
        IsCasting = true;

        MyAnimator.SetBool("cast", IsCasting);
        foreach (GearSoket soket in sokets)
        {
            soket.MyAnimator.SetBool("cast", IsCasting);
        }
        yield return new WaitForSeconds(castable.MyCastTime);

        denieCast();
    }
    private IEnumerator CastRoutine(ICastable castable)
    {
        Transform currentTRGT = MyTrgt;
        yield return actionRoutine =StartCoroutine(ActionRoutine(castable));

        if (currentTRGT != null && inFront())
        {
            Spell tempSpell = skillBook.MyInstance.getSkill(castable.MyTitle);
            magikSpells m = Instantiate(tempSpell.SpellPrefab, transform.position, Quaternion.identity).GetComponent<magikSpells>();
            m.inicialize(currentTRGT, tempSpell.Dmg, transform);
            Mana.myVal -= tempSpell.Cost;
        }
    }
    private IEnumerator GatherRoutine(ICastable castable, List<Drop> items)
    {
        Transform currentTRGT = MyTrgt;
        yield return actionRoutine = StartCoroutine(ActionRoutine(castable));
        LootWindow.MyInstance.CreatePages(items);
    }
    public IEnumerator CraftRoutine(ICastable castable)
    {
        profession.AddItemsToInventory();
        yield return actionRoutine = StartCoroutine(ActionRoutine(castable));
    }
    public void castSpell(ICastable castable)
    {
        blockAppear();
        Spell spell = skillBook.MyInstance.getSkill(castable.MyTitle);
        if (!IsCasting && MyTrgt.GetComponentInParent<unit>().IsAlive && !IsMoving && inFront()&& Mana.myVal >= spell.Cost)
        {

            initRoutine = StartCoroutine(CastRoutine(castable));
        }
    }
    public void Gather(ICastable castable, List<Drop> items)
    {
        if(!IsCasting && !IsMoving)
        {
            initRoutine = StartCoroutine(GatherRoutine(castable, items));
            
        }
    }
    private bool inFront()
    {
        if (MyTrgt != null)
        {
            Vector3 trgtDir = (MyTrgt.transform.position - transform.position).normalized;
            RaycastHit2D hit = Physics2D.Raycast(transform.position, trgtDir, Vector2.Distance(transform.position, MyTrgt.transform.position), LayerMask.GetMask("block"));
            if (hit.collider == null)
            {

                return true;
            }
        }


        return false;

    }
    private void blockAppear()
    {
        foreach (blockCtrl b in blocks)
        {
            b.deactivate();
        }
        blocks[dirIndex].activate();
    }
    public override void denieCast()
    {
        skillBook.MyInstance.stopCast();
        base.denieCast();
        foreach (GearSoket soket in sokets)
        {
            soket.MyAnimator.SetBool("cast", IsCasting);
        }
    }

    public override void DenieInit()
    {
        base.denieCast();
    }

    public override void animateMove(float x, float y)
    {
        base.animateMove(x, y);
        if (IsMoving)
        {
            foreach (GearSoket soket in sokets)
            {
                soket.setAxis(x, y);
            }
        }
    }

    public override void activeLayerController(string layerName)
    {
        base.activeLayerController(layerName);
        foreach (GearSoket soket in sokets)
        {
            soket.activeLayerController(layerName);
        }
    }
    //public void Interact()
    //{
        
    //    if (MyInteractable != null)
    //    {
    //        MyInteractable.Interact();
            
    //    }
    //}
    
    //public void CheckInteraction()
    //{
    //    //wtf is going on
    //    Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, rad);
    //    foreach(Collider2D col in colliders)
    //    {
    //        if (col.GetComponent<IInteractable>()!=null) {
                
    //            MyInteractables.Add(col.GetComponent<IInteractable>());
    //        }
    //    }
    //}
    public override void ReceiveDMG(float dmg, Transform source)
    {
        base.ReceiveDMG(dmg, source);
    }
    public void GetXP(int xpAmount)
    {
        MyExp.myVal += xpAmount;
        
        sctManager.MyInstance.TextGen(xpAmount.ToString(), transform.position, SCTType.EXP, false);
        if (MyExp.myVal >= MyExp.maxVal)
        {
            StartCoroutine(Levelup());
        }
    }
    private IEnumerator Levelup()
    {
        while(!MyExp.IsFull)
        {
            yield return null;
        }
        MyLevel++;
        Instantiate(LvlUpEffect,transform.position+Vector3.down,Quaternion.Euler(270f,0,0));
        lvlText.text = MyLevel.ToString();
        MyExp.maxVal = Mathf.Floor((700 * Mathf.Pow(MyLevel, 2)));
        MyExp.myVal = MyExp.MyOverflow;
        
        MyExp.ResetValue();
        if(MyLevel == 50)
        {
            AbilityPoints.MyInstance.MyAP += fiftyAP;
        }
        else if (MyLevel == 100)
        {
            AbilityPoints.MyInstance.MyAP += hundAP;
            
        }
        else if (MyLevel % 10 == 0)
        {
            AbilityPoints.MyInstance.MyAP += tenthAP;
        }
        else
        {

            AbilityPoints.MyInstance.MyAP += basicAP;
            
        }

        if (MyExp.myVal >= MyExp.maxVal)
        {
            StartCoroutine(Levelup());
        }
        Health.Improve(initHealth);
        Mana.Improve(initMana);
        Stamina.Improve(initStamina);

    }
    public void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.tag=="Enemy"|| collision.tag == "interacteble")
        {
            IInteractable interactable = collision.GetComponent<IInteractable>()        ;
            if (!MyInteractables.Contains(interactable))
            {
                MyInteractables.Add(interactable);
            }
        }
    }
    public void OnTriggerExit2D(Collider2D collision)
    {
        
        if (collision.tag == "Enemy" || collision.tag == "interacteble")
        {
            if (MyInteractables.Count > 0)
            {
                IInteractable interactable = MyInteractables.Find(x => x == collision.GetComponent<IInteractable>());
                if (interactable != null)
                {
                    interactable.StopInteract();

                }
                MyInteractables.Remove(interactable);
            }
            //if (MyInteractable != null)
            //{
               
            //    MyInteractable.StopInteract();
            //    MyInteractable = null;
            //    //MyInteractables.Clear();

            //}
        }
    }

    public void TeleportPlayerTo(GameObject destination)
    {
        transform.position = destination.transform.position;
    }
    public void SetDefaultValues()
    {
        Health.inicialize(initHealth, initHealth);
        Mana.inicialize(initMana, initMana);
        Stamina.inicialize(initStamina, initStamina);

        MyExp.inicialize(0, (int)(700 * Mathf.Pow(MyLevel, 2)));
        lvlText.text = MyLevel.ToString();
        
        MyGold = 7500;
        MyAlignment = Alignment(MyReputation, MyLawfullness);
    }

}
